home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xhearts
/
hearts_dist.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-09
|
11KB
|
442 lines
/*
* hearts_dist - distributor for hearts
*
* Keeps track of games in progress and allows new players to select which
* game to join or start a new game.
*
*
* Commands to hearts player:
* tn Following info regards table n (n is unique identifier).
* hn Now playing hand n.
* rn Now playing round n.
* pn<name> Player n is <name>.
*
* xn Table n has exited (game over).
* g Get table number to join.
* cn Connect to dealer on port n.
*
* Commands from hearts player:
* jn Join table n.
* n Start new game.
*
* Commands to dealer:
* none yet?!?
*
* Commands from dealer:
* hn Now playing hand n.
* rn Now playing round n.
* pn<name> Player n is <name>.
*
*/
/*
* MODIFICATION HISTORY
*
* S001 rr@sco.com 14 May 93
* - Use Internet Domain sockets rather than Unix Domain sockets
* S002 mikep@sco.com 22 June 93
* - Fix bug in socket call. Need to save the fd in socks[x]
* Note this don't work yet.
*/
#include "misc.h"
#include "defs.h"
#include "local.h"
#include <string.h>
#include <malloc.h>
typedef struct table *table_ptr;
struct table {
table_ptr next_table; /* Points to next table entry */
int table_id; /* Unique identifier */
char player_name[4][9]; /* Name of players at table */
int hand; /* Current dealer hand (1..4) */
int round; /* Current round (1..13) */
int port_num; /* Port # assigned */
int socket; /* File descriptor for dealer */
int pid; /* Process id for dealer */
};
typedef struct empty_table *empty_ptr;
struct empty_table {
empty_ptr next_empty;
int port_num; /* Available port # */
};
typedef struct new_comer *new_ptr;
struct new_comer {
new_ptr next_new_comer;
int socket; /* File descriptor */
};
table_ptr first_table;
empty_ptr first_empty;
new_ptr first_new_comer;
int main_sock,
next_port, /* Next port to assign */
unique_id;
/*
* clear_table - dealer went away; drop that table.
*/
clear_table(tbl_ptr)
table_ptr tbl_ptr;
{
table_ptr prev_ptr = NULL;
table_ptr cur_ptr;
empty_ptr temp_empty, cur_empty;
new_ptr cur_new_comer;
char buf[16];
while (wait(0) != tbl_ptr->pid) /* Wait for process to die */
;
(void) close(tbl_ptr->socket);
/*
* Inform new-comers
*/
(void) sprintf(buf, "x%d", tbl_ptr->table_id);
for (cur_new_comer = first_new_comer; cur_new_comer;
cur_new_comer = cur_new_comer->next_new_comer)
write_socket(cur_new_comer->socket, buf);
for (cur_ptr = first_table; cur_ptr != tbl_ptr;
cur_ptr = cur_ptr->next_table)
prev_ptr = cur_ptr;
if (prev_ptr)
prev_ptr->next_table = tbl_ptr->next_table;
else
if ((first_table = tbl_ptr->next_table) == NULL &&
first_new_comer == NULL)
exit(0); /* No more dealers */
;
if (first_table) {
temp_empty = (empty_ptr) malloc(sizeof(struct empty_table));
temp_empty->next_empty = NULL;
temp_empty->port_num = tbl_ptr->port_num;
free((char *) tbl_ptr);
if (first_empty) {
for (cur_empty = first_empty; cur_empty->next_empty;
cur_empty = cur_empty->next_empty) ;
cur_empty->next_empty = temp_empty;
}
else
first_empty = temp_empty;
}
}
/*
* drop_new_comer - New comer exited
*/
drop_new_comer(dead_new_comer)
new_ptr dead_new_comer;
{
new_ptr cur_new_comer,
prev_new_comer = NULL;
(void) close(dead_new_comer->socket);
for (cur_new_comer = first_new_comer; cur_new_comer != dead_new_comer;
cur_new_comer = cur_new_comer->next_new_comer)
prev_new_comer = cur_new_comer;
if (prev_new_comer)
prev_new_comer->next_new_comer = dead_new_comer->next_new_comer;
else
first_new_comer = dead_new_comer->next_new_comer;
free((char *) dead_new_comer);
if ((first_table == NULL) && (first_new_comer == NULL))
exit(0); /* Nobody connected */
}
/*
* new_player - New player has connected. Inform of games in progress and
* request game to be joined.
*/
new_player()
{
int new_socket; /* new file descriptor */
char buf[64];
struct sockaddr_in sockad;
int ssize; /* makes accept happy */
int i;
new_ptr cur_new_comer, temp_new_comer;
table_ptr cur_ptr;
/*
* add whoever's waiting
*/
ssize = sizeof (sockad);
if ((new_socket = accept(main_sock, &sockad, &ssize)) == -1) {
perror("accept");
exit(-1);
}
/*
* add to list of new_comers
*/
temp_new_comer = (new_ptr) malloc(sizeof(struct new_comer));
temp_new_comer->next_new_comer = NULL;
temp_new_comer->socket = new_socket;
if (first_new_comer) {
for (cur_new_comer = first_new_comer;
cur_new_comer->next_new_comer;
cur_new_comer = cur_new_comer->next_new_comer) ;
cur_new_comer->next_new_comer = temp_new_comer;
}
else {
first_new_comer = temp_new_comer;
first_new_comer->next_new_comer = NULL;
}
/*
* send info on games in progress
*/
for (cur_ptr = first_table; cur_ptr; cur_ptr = cur_ptr->next_table) {
(void) sprintf(buf, "t%d", cur_ptr->table_id);
write_socket(new_socket, buf);
(void) sprintf(buf, "h%d", cur_ptr->hand);
write_socket(new_socket, buf);
(void) sprintf(buf, "r%d", cur_ptr->round);
write_socket(new_socket, buf);
for (i = 0; i < 4; i++) {
(void) sprintf(buf, "p%d%s", i, cur_ptr->player_name[i]);
write_socket(new_socket, buf);
}
}
write_socket(new_socket, "g");
}
tell_new_comers(buf)
char *buf;
{
new_ptr cur_new;
for (cur_new = first_new_comer; cur_new;
cur_new = cur_new->next_new_comer)
write_socket(cur_new->socket, buf);
}
/*
* join - join an existing table. table_num is unique identifier for table.
*/
join(table_num, socket)
int table_num, socket;
{
table_ptr cur_ptr;
char buf[16];
for (cur_ptr = first_table; cur_ptr && cur_ptr->table_id != table_num;
cur_ptr = cur_ptr->next_table) ;
if (cur_ptr) {
(void) sprintf(buf, "c%d", cur_ptr->port_num);
write_socket(socket, buf);
}
else
write_socket(socket, "g"); /* Table doesn't exist?!? */
}
/*
* new_table - start new hearts game.
*/
new_table(cur_new_comer)
new_ptr cur_new_comer;
{
table_ptr cur_table, new_tbl_ptr;
empty_ptr tmp_empty;
int i, socks[2];
int dealer_port, dealer_socket, retry = 0;
char buf[16], filename[1024];
new_tbl_ptr = (table_ptr) malloc(sizeof(struct table));
new_tbl_ptr->next_table = NULL;
new_tbl_ptr->table_id = ++unique_id;
for (i = 0; i < 4; i++)
(void) strcpy(new_tbl_ptr->player_name[i], "<empty>");
/*
* Assign a port. Reassign a used port if available.
*/
do {
if (first_empty) {
dealer_port = first_empty->port_num;
tmp_empty = first_empty;
first_empty = first_empty->next_empty;
free((char *) tmp_empty);
}
else
dealer_port = next_port++;
/*
* Make sure port is ok before assigning.
*/
if ((dealer_socket = open_socket(dealer_port)) == 0)
if (++ retry == 20) {
fputs("Can't open a dealer port!\n", stderr);
exit(1);
}
}
while (dealer_socket == 0);
new_tbl_ptr->port_num = dealer_port;
/*
* Open a socket pair to talk to dealer on.
*/
if (socks[0] = socket(AF_INET, SOCK_STREAM, 0) == -1) { /* S002 */
perror("socket[0]");
exit(1);
}
if (socks[1] = socket(AF_INET, SOCK_STREAM, 0) == -1) { /* S002 */
perror("socket[1]");
exit(1);
}
switch (new_tbl_ptr->pid = fork()) {
case 0:
(void) setpgrp (0, getpid());
(void) close(socks[0]);
if (socks[1] != 3)
(void) dup2(socks[1], 3); /* Remap to fd 3 */
if (dealer_socket != 4)
(void) dup2(dealer_socket, 4); /* Remap to fd 4 */
sprintf(filename, "%s/%s", HEARTSLIB, HEARTSD);
execl (filename, "heartsd", 0);
exit(1);
case -1:
perror("fork");
exit(1);
}
(void) close(socks[1]);
(void) close(dealer_socket);
new_tbl_ptr->socket = socks[0];
if (first_table) {
for (cur_table = first_table; cur_table->next_table;
cur_table = cur_table->next_table)
;
cur_table->next_table = new_tbl_ptr;
}
else
first_table = new_tbl_ptr;
/*
* Inform hearts player of port # to connect on.
*/
(void) sprintf(buf, "c%d", dealer_port);
write_socket(cur_new_comer->socket, buf);
}
main(argc, argv)
char **argv;
{
fd_type read_fd;
table_ptr cur_table;
new_ptr cur_new_comer;
char buf[64], tmp_buf[64];
int ret;
int table_num;
char debug = FALSE;
while (*++argv) {
if (**argv == '-') {
while (*++*argv) {
switch (**argv) {
case 'd':
debug = TRUE;
break;
default:
fprintf (stderr, "usage: hearts_dist [-d]\n");
exit (1);
break;
}
}
}
}
first_table = NULL;
first_empty = NULL;
first_new_comer = NULL;
next_port = DIST_PORT;
unique_id = 0;
if ((main_sock = open_socket(PORT)) == 0) {
fputs("Distributor port in use!\n", stderr);
exit(1);
}
if (!debug) {
/*
* Fork off and die. Thus hearts invoker wait() returns.
* This signals ready to connect.
*/
if (fork())
exit (0);
}
for (;;) {
fd_init(main_sock, &read_fd);
/*
* Build mask for dealers
*/
for (cur_table = first_table; cur_table;
cur_table = cur_table->next_table)
fd_set(cur_table->socket, &read_fd);
/*
* Build mask for new_comers
*/
for (cur_new_comer = first_new_comer; cur_new_comer;
cur_new_comer = cur_new_comer->next_new_comer)
fd_set(cur_new_comer->socket, &read_fd);
/*
* Wait for something to happen
*/
if (select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
(struct timeval *) 0)) {
if (fd_isset(main_sock, read_fd))
new_player();
for (cur_table = first_table; cur_table;
cur_table = cur_table->next_table)
if (fd_isset(cur_table->socket, read_fd)) {
/*
* Message from dealer
*/
ret = read_socket(cur_table->socket, buf);
if (!ret) {
clear_table(cur_table);
break;
} else {
switch (buf[0]) {
case 'h' :
(void) sscanf(buf + 1, "%d", &cur_table->hand);
break;
case 'r' :
(void) sscanf(buf + 1, "%d", &cur_table->round);
break;
case 'p' :
(void) strcpy(cur_table->player_name[buf[1] - '0'], buf + 2);
}
(void) sprintf(tmp_buf, "t%d", cur_table->table_id);
tell_new_comers(tmp_buf);
tell_new_comers(buf);
}
}
for (cur_new_comer = first_new_comer; cur_new_comer;
cur_new_comer = cur_new_comer->next_new_comer)
if (fd_isset(cur_new_comer->socket, read_fd)) {
/*
* Message from newcomer
*/
ret = read_socket(cur_new_comer->socket, buf);
if (ret)
switch (buf[0]) {
case 'j' :
(void) sscanf(buf + 1, "%d", &table_num);
join(table_num, cur_new_comer->socket);
break;
case 'n' :
new_table(cur_new_comer);
}
else {
drop_new_comer(cur_new_comer);
break;
}
}
}
}
}